/**
 * Software License, Version 1.0
 *
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 *
 *
 *Redistribution and use in source and binary forms, with or without
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For
 * further information contact the Community Grids Lab at
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and
 * wherever such third-party acknowledgments normally appear.
 *
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering,
 * shall not be used to endorse or promote products derived from this software
 * without prior written permission from Indiana University.  For written
 * permission, please contact the Advanced Research and Technology Institute
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering,
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 *
 *
 * Indiana University provides no reassurances that the source code provided
 * does not infringe the patent or any other intellectual property rights of
 * any other entity.  Indiana University disclaims any liability to any
 * recipient for claims brought by any other entity based on infringement of
 * intellectual property rights or otherwise.
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION
 *GENERATED USING SOFTWARE.
 */

package cgl.narada.wsinfra.wsr.impl;

import java.util.Calendar;
import java.util.Vector;

import javax.xml.namespace.QName;

import org.apache.xmlbeans.GDuration;

import cgl.narada.wsinfra.WsMessageFlow;
import cgl.narada.wsinfra.WsProcessor;
import cgl.narada.wsinfra.exception.DeploymentException;
import cgl.narada.wsinfra.exception.IncorrectExchangeException;
import cgl.narada.wsinfra.exception.MessageFlowException;
import cgl.narada.wsinfra.exception.ProcessingException;
import cgl.narada.wsinfra.exception.UnknownExchangeException;
import cgl.narada.wsinfra.exception.WsFaultException;
import cgl.narada.wsinfra.schemas.addressing.ActionDocument;
import cgl.narada.wsinfra.schemas.addressing.EndpointReferenceType;
import cgl.narada.wsinfra.schemas.addressing.FromDocument;
import cgl.narada.wsinfra.schemas.soap.EnvelopeDocument;
import cgl.narada.wsinfra.schemas.soap.FaultDocument;
import cgl.narada.wsinfra.schemas.wsr.MessageIdType;
import cgl.narada.wsinfra.schemas.wsr.PollRequestDocument;
import cgl.narada.wsinfra.schemas.wsr.PollRequestType;
import cgl.narada.wsinfra.schemas.wsr.RefToMessageIdsType;
import cgl.narada.wsinfra.schemas.wsr.ReplyPatternType;
import cgl.narada.wsinfra.schemas.wsr.RequestDocument;
import cgl.narada.wsinfra.schemas.wsr.RequestType;
import cgl.narada.wsinfra.schemas.wsr.ResponseDocument;
import cgl.narada.wsinfra.schemas.wsr.SequenceNumRangeType;
import cgl.narada.wsinfra.schemas.wsr.SequenceNumType;
import cgl.narada.wsinfra.util.FaultCreator;
import cgl.narada.wsinfra.wsa.AddressingHeaders;
import cgl.narada.wsinfra.wsa.WsaEnvelopeCreator;
import cgl.narada.wsinfra.wsa.WsaEprRules;
import cgl.narada.wsinfra.wsa.WsaFaultRules;
import cgl.narada.wsinfra.wsa.WsaProcessingFactory;
import cgl.narada.wsinfra.wsr.WsrActions;
import cgl.narada.wsinfra.wsr.WsrConstants;
import cgl.narada.wsinfra.wsr.WsrElementCreation;
import cgl.narada.wsinfra.wsr.WsrExchangeInfo;
import cgl.narada.wsinfra.wsr.WsrNodeUtils;
import cgl.narada.wsinfra.wsr.WsrProcessingFactory;
import cgl.narada.wsinfra.wsr.WsrQNames;
import cgl.narada.wsinfra.wsr.WsrRequestCreator;
import cgl.narada.wsinfra.wsr.WsrResponseCreator;
import cgl.narada.wsinfra.wsr.storage.WsrGroupInfoStorageOperations;
import cgl.narada.wsinfra.wsr.storage.WsrProtocolStorageOperations;
import cgl.narada.wsinfra.wsr.storage.WsrStorageException;
import cgl.narada.wsinfra.wsr.storage.WsrStorageService;
import cgl.narada.wsinfra.wsr.storage.impl.WsrGroupInfoImpl;
import cgl.narada.wsinfra.wsr.storage.impl.WsrGroupTerminationInfoImpl;
import cgl.narada.wsinfra.wsr.storage.impl.WsrStorageWidgetImpl;


/**
 * @author Damodar Yemme, Sima Patel
 * $Created on February 16, 2005, 2:31 PM $
 * $Version 1.0
 */
public class WsrSinkNodeHelper extends WsProcessor{
    private static final WsrSinkNodeHelper instance = new WsrSinkNodeHelper();

    private WsMessageFlow wsMessageFlow;

    private FaultCreator faultCreator;

    private EndpointReferenceType sinkEpr;

    private WsrStorageService wsrStorageServiceSinkHelper;
    private WsrProtocolStorageOperations wsrProtocolStorageOperations;
    private WsrGroupInfoStorageOperations wsrGroupInfoStorageOperations;

    private WsaEprRules wsaEprRules;
    private WsaFaultRules wsaFaultRules;
    private WsaEnvelopeCreator wsaEnvelopeCreator;

    private WsrFaultsImpl wsrFaultsImpl;
    private WsrActions wsrActions;
    private WsrQNames wsrQNames;
    private WsrNodeUtils wsrNodeUtils;
    private WsrUtil wsrUtil;
    private WsrElementCreation wsrElementCreation;
    private WsrResponseCreator wsrResponseCreator;
    private WsrRequestCreator wsrRequestCreator;


    private String moduleName = "WsrSinkNodeHelper: ";

    /** Creates a new instance of WsrSinkNodeHelper */
    public WsrSinkNodeHelper() {
        faultCreator = FaultCreator.getInstance();
        wsrQNames = WsrQNames.getInstance();
        wsrActions = WsrActions.getInstance();
        wsrFaultsImpl = WsrFaultsImpl.getInstance();
        wsrNodeUtils = WsrProcessingFactory.getWsrNodeUtils();
        wsrUtil = WsrUtil.getInstance();
        wsrElementCreation = WsrProcessingFactory.getWsrElementCreation();

        wsaFaultRules = WsaProcessingFactory.getWsaFaultRules();
        wsaEprRules = WsaProcessingFactory.getWsaEprRules();
        wsaEnvelopeCreator = WsaProcessingFactory.getWsaEnvelopeCreator();
        wsrResponseCreator = WsrProcessingFactory.getWsrResponseCreator();
        wsrRequestCreator = WsrProcessingFactory.getWsrRequestCreator();
    }
    public static WsrSinkNodeHelper getInstance() {
        return instance;
    }
    public void initialize(WsrStorageService wsrStorageService)
                throws DeploymentException {
        this.wsrStorageServiceSinkHelper = wsrStorageService;
        if (wsrStorageServiceSinkHelper == null) {
            throw new DeploymentException(moduleName+"SinkHelperStorageService is NULL!");
        }
        try {
            wsrProtocolStorageOperations =
                wsrStorageServiceSinkHelper.getWsrProtocolStorageOperations();
            wsrGroupInfoStorageOperations =
                wsrStorageServiceSinkHelper.getWsrGroupInfoStorageOperations();

        } catch (WsrStorageException wsrStorageException) {
            String reason = moduleName + "Problems initializing storage"+
                "services\n" + wsrStorageException.toString();
            throw new DeploymentException(reason);
        }

    }
    public boolean processExchange(EnvelopeDocument envelopeDocument,
                                int direction)
                throws UnknownExchangeException, IncorrectExchangeException,
                       ProcessingException,  MessageFlowException{
    	String errorReport = null;

        errorReport = moduleName + "Should NOT have this exchange. This is "
          + "just a helper to the WsrmSinkNode. ";

        if (errorReport != null) {
          throw new ProcessingException(errorReport);
        }

        return false;
    }
    /** Sets the message flow which the processor should use */
    public void setMessageFlow(WsMessageFlow wsMessageFlow)
                throws DeploymentException {
        this.wsMessageFlow = wsMessageFlow;
    }

    /** Gets the message flow which the processor should use. */
    public WsMessageFlow getMessageFlow() {
        return wsMessageFlow;
    }
    public void setEndpointReference(EndpointReferenceType endpointReference) {
        this.sinkEpr = endpointReference;
    }

    /** This method checks the probles in Request Document  */
    public boolean checkForProblemsInRequestDocument(
                                         RequestDocument requestDocument,
                                         AddressingHeaders addressingHeaders)
                   throws WsFaultException, WsrStorageException,
                          MessageFlowException{
        if(!checkForInvalidRequest(requestDocument, addressingHeaders)){
            return false;
        }
        return true;
    }
    private boolean checkForInvalidRequest(RequestDocument requestDocument,
                                           AddressingHeaders addressingHeaders)
                    throws WsFaultException, MessageFlowException,
                           WsrStorageException{
        QName fault = wsrFaultsImpl.getInvalidRequest();
        RequestType requestType = requestDocument.getRequest();
        String errorReport = "Problems in Request Element: ";

        if(!wsrNodeUtils.hasMessageIDElement(requestDocument)){
            errorReport += "Request:MessageId Element CANNOT be null";

            throwInvalidMessageFaultException(errorReport, addressingHeaders);
        }
        if(!checkForInvalidMessageId(requestDocument, addressingHeaders)){
            return false;
        }
        if(!wsrNodeUtils.hasMessageExpiryTimeElement(requestDocument)){
            errorReport += "Request:ExpiryTime[Message Expiry Time]"+
                "CANNOT be null";
            processRMFault(requestDocument,addressingHeaders,fault,errorReport);
            return false;
        }
        if(!wsrNodeUtils.hasReplyPatternElement(requestDocument)){
            errorReport += "Request:ReplyPattern  Element CANNOT be null";
            processRMFault(requestDocument,addressingHeaders,fault,errorReport);
            return false;
        }
        if(!checkForInvalidReplyPattern(requestDocument,addressingHeaders)){
            return false;
        }
        return true;

    }
    private boolean checkForInvalidMessageId(RequestDocument requestDocument,
                                             AddressingHeaders addressingHeaders)
                    throws WsFaultException, WsrStorageException,
                           MessageFlowException{
        RequestType requestType = requestDocument.getRequest();
        MessageIdType messageIdType = requestType.getMessageId();
        String errorReport = "Problems with Invalid MessageID. ";
        if(!wsrNodeUtils.hasGroupId(requestDocument)){
            errorReport += "Request:MessageId:GroupId CANNOT be null";
            throwInvalidMessageFaultException(errorReport, addressingHeaders);
        }
        if(!messageIdType.isSetSequenceNum()){
            errorReport += "Request:MessageId:SequenceNumber CANNOT be null";
            throwInvalidMessageFaultException(errorReport, addressingHeaders);
        }
        if(messageIdType.getSequenceNum().getNumber()== null){
            errorReport += "Request:MessageId:SequenceNumber:Number CANNOT"+
                " be null";
            throwInvalidMessageFaultException(errorReport, addressingHeaders);
        }
        if(!checkForInvalidMessageParameters(requestDocument,addressingHeaders)){
            return false;
        }
        return true;
    }
    private boolean checkForInvalidMessageParameters(
                                            RequestDocument requestDocument,
                                            AddressingHeaders addressingHeaders)
                 throws WsrStorageException, MessageFlowException{

        QName fault = wsrFaultsImpl.getInvalidMessageParameters();
        String errorReport = "Problems in Message Parameters: ";
        RequestType requestType = requestDocument.getRequest();
        MessageIdType messageIdType = requestType.getMessageId();
        SequenceNumType sequenceNumType = messageIdType.getSequenceNum();
        if(sequenceNumType.isSetGroupExpiryTime() &&
                                  sequenceNumType.isSetGroupMaxIdleDuration()){
            errorReport += "Request:MessageId:SequenceNumber: GroupExpiryTime "+
                            "and GroupMaxIdleDuration both CANNOT be "+
                            "present at the same time";
            processRMFault(requestDocument,addressingHeaders,fault,errorReport);
            return false;
        }
        if(sequenceNumType.isSetGroupExpiryTime()&&
        		wsrNodeUtils.hasMessageExpiryTimeElement(requestDocument)){
            if(requestType.getExpiryTime().getTimeInMillis() >
               sequenceNumType.getGroupExpiryTime().getTimeInMillis()){
                errorReport += "Request:ExpiryTime value is greater than  " +
                               "GroupExpiryTime";
                processRMFault(requestDocument, addressingHeaders, fault,
                                                                  errorReport);
                return false;
            }
        }
        return true;

    }
    private boolean checkForInvalidReplyPattern(
                                            RequestDocument requestDocument,
                                            AddressingHeaders addressingHeaders)
                    throws MessageFlowException, WsrStorageException{
        QName fault = wsrFaultsImpl.getInvalidReplyPattern();
        String errorReport = "Problems in Reply Pattern: ";
        RequestType requestType = requestDocument.getRequest();
        if(wsrNodeUtils.hasReplyPatternElement(requestDocument)){
        	ReplyPatternType replyPatternType = requestType.getReplyPattern();
            if(replyPatternType.getValue().toString().equalsIgnoreCase
                                                                 ("Callback")){
                if((replyPatternType.isSetReplyTo() == false) ||
                	(replyPatternType.isSetReplyTo()&&
                		replyPatternType.getReplyTo().isSetReferenceScheme()==
                		                                                    false)){
                            errorReport += "Request:ReplyPattern:ReplyTo " +
                            "element must be present in case of callback " +
                            "reply pattern";
                            processRMFault(requestDocument,addressingHeaders,
                                                           fault,
                                                           errorReport);
                            return false;
                }

           	}
        }
        return true;
    }
    private void processRMFault(RequestDocument requestDocument,
                                AddressingHeaders addressingHeaders,
                                QName fault, String reason)
                 throws WsrStorageException, MessageFlowException{

        WsrGroupInfoImpl wsrGroupInfoImpl = null;
        WsrGroupTerminationInfoImpl wsrGroupTerminationInfoImpl = null;
        WsrStorageWidgetImpl wsrStorageWidgetImpl = null;
        ResponseDocument responseDocument = null;
        RequestType requestType = requestDocument.getRequest();
        MessageIdType messageIdType = requestType.getMessageId();
        SequenceNumType sequenceNumType = messageIdType.getSequenceNum();
        String groupId = messageIdType.getGroupId().trim();
        long sequenceNumber = messageIdType.getSequenceNum().getNumber().
                                                                    longValue();
        if(!wsrGroupInfoStorageOperations.isGroupExists(groupId)){
            wsrGroupInfoImpl = createGroupInfoFromRequestDocument(
                                            requestDocument, addressingHeaders);
            wsrGroupInfoImpl.setLastSequenceNumber(0);
            wsrGroupTerminationInfoImpl = new WsrGroupTerminationInfoImpl(
                                                                       groupId);
            wsrGroupTerminationInfoImpl.setIsSource(false);
        }else{
	    System.out.println("ITs a known group");
            wsrGroupInfoImpl =
                wsrGroupInfoStorageOperations.getGroupInfoUsingGroupId(groupId);
            wsrGroupTerminationInfoImpl =
                wsrProtocolStorageOperations.getGroupTerminationInfo(groupId);

        }
        wsrStorageWidgetImpl = createMessageInfoFromRequestDocument(
                                                               requestDocument);
        updateGroupTerminationInfo(wsrGroupTerminationInfoImpl,
                                   wsrGroupInfoImpl.getGroupExpiryTime(),
                                   wsrGroupInfoImpl.getGroupMaxIdleDuration(),
                                   wsrStorageWidgetImpl.getMessageExpiryTime());
        if(wsrGroupTerminationInfoImpl.isGroupClosed()){
	    if(wsrGroupInfoStorageOperations.isKnownGroup(groupId) == false &&
              sequenceNumType.isSetLast()== true  && sequenceNumType.getLast() == true){
                wsrElementCreation.newResponse(responseDocument,groupId,
                                    wsrFaultsImpl.getGroupAborted().toString());
            }else{
		  wsrElementCreation.newResponse(responseDocument, groupId,
                                                                 sequenceNumber,
                     sequenceNumber,wsrFaultsImpl.getGroupAborted().toString());
            }
            EnvelopeDocument newEnvelopeDocument = createResponse(
                                                              addressingHeaders,
                                                              requestDocument,
                                                              responseDocument);
	    wsrProtocolStorageOperations.storeGroupTerminationInfo(
                                                   wsrGroupTerminationInfoImpl);
            wsrGroupInfoStorageOperations.storeCreatedGroup(wsrGroupInfoImpl);
            enrouteToNetwork(newEnvelopeDocument);
            return;

        }
        if(wsrGroupInfoStorageOperations.isGroupExists(groupId) == false &&
              sequenceNumType.isSetLast()== true && sequenceNumType.getLast() == true){
	     responseDocument = wsrElementCreation.newResponse(responseDocument,
                                                              groupId,
                                           fault.toString());
        }else{
	    responseDocument = wsrElementCreation.newResponse(responseDocument,
                                           groupId,
                                           sequenceNumber,
                                           sequenceNumber,fault.toString());
        }
        EnvelopeDocument newEnvelopeDocument = createResponse(
                                                              addressingHeaders,
                                                              requestDocument,
                                                              responseDocument);
        addFaultToSoapBody(newEnvelopeDocument, reason);
        enrouteToNetwork(newEnvelopeDocument);
        if(sequenceNumType.isSetLast()== true && sequenceNumType.getLast() == true){
            wsrGroupTerminationInfoImpl.setLastMessageOfGroup(true);
        }
        wsrStorageWidgetImpl.setMessageStatus(WsrConstants.MESSAGE_FAULTED);
        wsrStorageWidgetImpl.setMessageFault(fault);
        wsrStorageWidgetImpl.setEnvelope(newEnvelopeDocument);
        wsrProtocolStorageOperations.storeGroupTerminationInfo
                                                  (wsrGroupTerminationInfoImpl);
        wsrGroupInfoStorageOperations.storeCreatedGroup(wsrGroupInfoImpl);
        wsrProtocolStorageOperations.store(wsrStorageWidgetImpl);
    }
    /** This method will create response based on reply pattern.*/
    public EnvelopeDocument createResponse(AddressingHeaders addressingHeaders,
                                           RequestDocument requestDocument,
                                           ResponseDocument responseDocument) {
    	String replyTo = null;
        String replyPattern = null;
        if(wsrNodeUtils.hasReplyPatternElement(requestDocument)){
	        replyPattern = requestDocument.getRequest()
	                                       .getReplyPattern().getValue().toString();
	        if(replyPattern.equalsIgnoreCase(WsrConstants.REPLY_PATTERN_CALLBACK)&&
	           requestDocument.getRequest().getReplyPattern().isSetReplyTo() &&
			   requestDocument.getRequest().getReplyPattern().getReplyTo().
			                                                  isSetReferenceScheme()){
	        	replyTo= requestDocument.getRequest().
				               getReplyPattern().getReplyTo().getReferenceScheme();
	        }
        }
        EnvelopeDocument newEnvelopeDocument =
                                             getSoapEnvelope(addressingHeaders,
                                             	             replyTo);
        if(replyPattern == null){
            wsrResponseCreator.addResponse(newEnvelopeDocument,responseDocument);
        }else{
        if(replyPattern.equalsIgnoreCase(WsrConstants.REPLY_PATTERN_RESPONSE)){
            wsrRequestCreator.addRequest(newEnvelopeDocument, requestDocument);
            wsrResponseCreator.addResponse(newEnvelopeDocument,responseDocument);
        }
        if(replyPattern.equalsIgnoreCase(WsrConstants.REPLY_PATTERN_CALLBACK)){
            wsrResponseCreator.addResponse(newEnvelopeDocument,responseDocument);
        }
        }
        return newEnvelopeDocument;
    }
    public EnvelopeDocument getSoapEnvelope(AddressingHeaders addressingHeaders,
    		                                String replyTo){
    	EndpointReferenceType to = null;
    	System.out.println("Reply To:"+ replyTo);
    	if(replyTo == null){
    		to = wsaEprRules.sendTo(addressingHeaders);
    	}else{
    		to = EndpointReferenceType.Factory.newInstance();
    		to.addNewAddress().setStringValue(replyTo);
    	}
    	System.out.println("To Elment is:"+ to.toString());
        FromDocument from = FromDocument.Factory.newInstance();
        from.setFrom(sinkEpr);
        ActionDocument action = ActionDocument.Factory.newInstance();
        action.addNewAction().setStringValue(wsrActions.getProcessResponse());
        EnvelopeDocument envelopeDocument =
                          wsaEnvelopeCreator.createSoapEnvelope(to,from,action);
        return envelopeDocument;
    }

    private void addFaultToSoapBody(EnvelopeDocument envelopeDocument,
                                            String reason){
        FaultDocument faultDocument = faultCreator.getFaultDocument(
                                     wsrFaultsImpl.getSoapSenderQName(),reason);
        faultCreator.copyFaultIntoSOAPBody(envelopeDocument,faultDocument);
    }

    /** create GroupInfo from Request Document*/
    public WsrGroupInfoImpl createGroupInfoFromRequestDocument(
                                           RequestDocument requestDocument,
                                           AddressingHeaders addressingHeaders){

        EndpointReferenceType sourceAddress =
                                    EndpointReferenceType.Factory.newInstance();
        String source = addressingHeaders.getFrom().toString();
        sourceAddress.addNewAddress().setStringValue(source);
        // Check for the messageId from the request document.
        RequestType requestType = requestDocument.getRequest();
        String groupID = requestType.getMessageId().getGroupId();
        WsrGroupInfoImpl wsrGroupInfoImpl = new WsrGroupInfoImpl(groupID);
        // Check if GroupExpiyTime there.
        if(requestType.getMessageId().getSequenceNum().isSetGroupExpiryTime()){
            wsrGroupInfoImpl.setGroupExpiryTime(requestType.getMessageId()
                                        .getSequenceNum().getGroupExpiryTime());
        }
        //Check if GroupMaxIdleDuration there.
        if(requestType.getMessageId().getSequenceNum().
                                                   isSetGroupMaxIdleDuration()){
            wsrGroupInfoImpl.setGroupMaxIdleDuration(requestType.getMessageId()
                                   .getSequenceNum().getGroupMaxIdleDuration());
        }
        wsrGroupInfoImpl.setIsSource(false);
        wsrGroupInfoImpl.setSource(sourceAddress);
        wsrGroupInfoImpl.setDestination(sinkEpr);
        return wsrGroupInfoImpl;
    }
    /** Create MessageInfo from Requestdocument*/
    public WsrStorageWidgetImpl createMessageInfoFromRequestDocument(
                                               RequestDocument requestDocument){
        RequestType requestType = requestDocument.getRequest();
        MessageIdType messageIdType = requestType.getMessageId();
        SequenceNumType sequenceNumType = messageIdType.getSequenceNum();

        String groupId = messageIdType.getGroupId();
        long sequenceNumber = sequenceNumType.getNumber().longValue();

        WsrStorageWidgetImpl wsrStorageWidgetImpl = new WsrStorageWidgetImpl(
                                                       groupId, sequenceNumber);
        if(wsrNodeUtils.hasMessageExpiryTimeElement(requestDocument)){
            wsrStorageWidgetImpl.setMessageExpiryTime(
                                                   requestType.getExpiryTime());
        }
        ReplyPatternType replyPatternType = null;
        if(wsrNodeUtils.hasReplyPatternElement(requestDocument)){
            replyPatternType = requestType.getReplyPattern();
            wsrStorageWidgetImpl.setReplyPattern(
                                        replyPatternType.getValue().toString());
            if(replyPatternType.getValue().toString().equalsIgnoreCase(
                    WsrConstants.REPLY_PATTERN_CALLBACK) &&
					replyPatternType.isSetReplyTo()&&
					replyPatternType.getReplyTo().isSetReferenceScheme()
					&& replyPatternType.getReplyTo().getReferenceScheme()!= null){
            		wsrStorageWidgetImpl.setReplyTo(
            				replyPatternType.getReplyTo().getReferenceScheme());
            	}
            }
        return wsrStorageWidgetImpl;
    }
    /** update groupTerminationInfo object according to specified parameters*/
    public void updateGroupTerminationInfo(
                            WsrGroupTerminationInfoImpl wsrGroupTerminationInfo,
                            Calendar groupExpiryTime,
                            GDuration groupMaxIdleDuration,
                            Calendar messageExpiryTime){
	System.out.println("I am in updategroupterminationinfo");
        if(groupExpiryTime != null){
            if(wsrUtil.isExpiryTimePassed(groupExpiryTime))
                wsrGroupTerminationInfo.setGroupExpiryTimePassed(true) ;
        }
	System.out.println("Expiry time is fine");
        if(groupMaxIdleDuration != null){
            if(wsrUtil.isDurationPassed(groupMaxIdleDuration))
                wsrGroupTerminationInfo.setGroupMaxIdleDurationPassed(true);
        }
	System.out.println("Duration is fine");
        if(messageExpiryTime != null){
            if(wsrUtil.isExpiryTimePassed(messageExpiryTime))
                wsrGroupTerminationInfo.setMessageExpired(true);
        }
    }
    /** Checks an exchange type for validity. If there are problems exceptions
    * are thrown. */
    public void checkExchangeType(WsrExchangeInfo wsrExchangeInfo,
                                  int direction)
                throws UnknownExchangeException, IncorrectExchangeException {

        if (direction == WsMessageFlow.FROM_NETWORK) {
            checkExchangeFromNetwork(wsrExchangeInfo);
        }

        if (direction == WsMessageFlow.FROM_APPLICATION) {
            checkExchangeFromApplication(wsrExchangeInfo);
        }
    }
    /** ONLY Exchanges containing ProcessRequestAction, ProcessPollRequestAction,
    * Request & PollRequest elements should be routed here. */
    private void checkExchangeFromNetwork(WsrExchangeInfo wsrExchangeInfo)
                 throws UnknownExchangeException, IncorrectExchangeException {

        String from = "Network. ";
        String problemElement = "";

        if (wsrExchangeInfo.isProcessResponse() ) {
            problemElement += " ProcessResponseAction";
        }

        if (wsrExchangeInfo.hasResponse() ) {
            problemElement += " Response";
        }

        if (!problemElement.equals("")) {
            throwIncorrectExchangeException(problemElement, from);
        }

        if (wsrExchangeInfo.hasRequest() || wsrExchangeInfo.hasPollRequest() ||
                                          wsrExchangeInfo.isProcessRequest() ||
                                      wsrExchangeInfo.isProcessPollRequest() ) {
            /** If this is true,the exchange is a valid one.Proceed to return */
            return;
        }
        String shouldHaveReceived =
               "ProcessRequest or ProcessPollReqeust or Request or PollRequest";
        throwUnknownExchangeException(shouldHaveReceived, from);
    }

    /** Only Exchanges containing ProcessResponseActions are valid. */
    private void checkExchangeFromApplication(WsrExchangeInfo wsrExchangeInfo)
                 throws UnknownExchangeException, IncorrectExchangeException {

        String from = "Application. ";
        String problemElement = "";
        if (wsrExchangeInfo.hasRequest() ) {
            problemElement += " Request ";
        }

        if (wsrExchangeInfo.hasResponse()) {
            problemElement += " Response ";
        }
        if (wsrExchangeInfo.hasPollRequest()) {
            problemElement += " PollRequest ";
        }

        if (wsrExchangeInfo.isProcessRequest() ) {
            problemElement += " ProcessRequestAction ";
        }

        if (wsrExchangeInfo.isProcessPollRequest() ) {
            problemElement += " ProcessPollRequestAction ";
        }

        if (!problemElement.equals("")) {
            throwIncorrectExchangeException(problemElement, from);
        }

    }
    /**This method will throw incorrect exchange exception.*/
    private void throwIncorrectExchangeException(String element, String from)
                 throws IncorrectExchangeException {
        String reason =  moduleName +
                           "Should NOT have received exchange with element [" +
                            element + "] from the " + from;
        throw new IncorrectExchangeException(reason);
    }
    /**This method will throw unknown exchange exception.*/
    private void throwUnknownExchangeException(String element, String from)
                 throws UnknownExchangeException {
        String reason =  moduleName +
              "No idea about processing exchange without elements [" + element +
              "] from the " + from + ".";
        throw new UnknownExchangeException(reason);
    }
    /** Throws an Invalid MessageFault exception based on the specified
    * parameters */
    public void throwInvalidMessageFaultException(String reason,
                                            AddressingHeaders addressingHeaders)
                throws WsFaultException {
        EndpointReferenceType faultTo =
                                   wsaFaultRules.sendFaultTo(addressingHeaders);

        WsFaultException wsFaultException =
                        new WsFaultException(wsrFaultsImpl.getSoapSenderQName(),
                                                                        reason);
        wsFaultException.setFaultTo(faultTo);

        throw wsFaultException;
    }

    /** check for problems in PollRequest Document*/
    public void checkForProblemsInPollRequestDocument(
                                        PollRequestDocument pollRequestDocument,
                                        AddressingHeaders addressingHeaders)
                throws WsFaultException{
        PollRequestType pollRequestType = pollRequestDocument.getPollRequest();
        //check for RefToMessageId Element in PollRequestDocument
        if(!wsrNodeUtils.hasRefToMessageIdsElement(pollRequestDocument)){
            String reason = "There should be atleast one "+
                "PollRequest:RefToMessageIds" +
                " element in PollRequestDocument";
            throwInvalidMessageFaultException(reason,addressingHeaders);
        }
        //check here for GroupId attribute of RefToMessageId Element
        RefToMessageIdsType[] refToMessageIdsType =
                                      pollRequestType.getRefToMessageIdsArray();
        for(int count =0; count< refToMessageIdsType.length; count++){
            String groupId = refToMessageIdsType[count].getGroupId();
            if(groupId == null){
                String reason = "RefToMessageIds: GroupId attribute can not be "
                  +"null in PollRequestDocument";
                throwInvalidMessageFaultException(reason, addressingHeaders);
            }
        }
        //check here for From and To elements in SequenceNumRange
        for(int index =0; index < refToMessageIdsType.length; index++){
            if(refToMessageIdsType[index].sizeOfSequenceNumRangeArray() != 0){
                SequenceNumRangeType[] sequenceNumRangeType =
                          refToMessageIdsType[index].getSequenceNumRangeArray();
                for(int i=0; i<sequenceNumRangeType.length; i++){
                    if(sequenceNumRangeType[i].getFrom()== null ||
                                       sequenceNumRangeType[i].getTo() == null){
                        String reason =
                        "RefToMessageIdsType:SequenceNumberRangeType:" +
                        "From or To element can not be null in "+
                        "PollRequestDocument";
                        throwInvalidMessageFaultException(reason,
                                                             addressingHeaders);
                    }
                }
            }
        }
        //check here for ReplyTo element, if present then
        //ReferenceScheme attribute must be present
        if(pollRequestType.isSetReplyTo()){
            if(!pollRequestType.getReplyTo().isSetReferenceScheme()){
                String reason = "ReplyTo:ReferenceScheme Attribure must be" +
                                " present in PollRequest";
                throwInvalidMessageFaultException(reason,addressingHeaders);
            }
        }

    }

    /** create Long Number array from Vector */
    public long[] createLongArrayFromVector(Vector vector){
        long[] numbers = new long[vector.size()];
        for(int index=0;index<vector.size();index++){
            numbers[index]=((Long)(vector.elementAt(index))).longValue();
        }
        return numbers;
    }

}
